function [result, err] = config_parse(infile, struct)
%
% function to parse a configuration file.
% the result is returned as a structure
% result.section.argument = value
% where
% section is defined by the [section] identifier
% argument is argument =
% and
% value is rhs of argument =.
%
% Thus:
% [channels]
% number = 5
% list = [1,2,3,4,5]
% returns a structure that is as follows:
% result.channels.number = 5
% result.channels.list = [1,2,3,4,5];
%
% the input to the routine is the infile. A structure is generated
% on output according to the text input read.
% if a struct is defined in the call, the output is initialized to this
% structure, and the parsing is checked against the names in the
% structure - if they do match, the values in the config file are
% accepted; if they do not match, a warning is printed and the
% argument is ignored.
%
% To allow the result to be an array, we also permit the following:
% at the start of the file, use the statement
% #array
% This sets the array counter to 1.
% the directive #increment in the input will increment the array
% counter, and subsequent inputs will be parsed into the next element
% of the strugure.
%
% 2 Dec 2004. Paul B. Manis, Ph.D., pmanis@med.unc.edu
%

result = [];
err = 0;
arrayflag = 0; % init with array mode off
arrayindex = 1;
fh = fopen(infile);
if(isempty(fh))
    err = 1;
    fprintf(1, 'File %s not found\n', infile);
    return;
end;
if(nargin == 2)
    fnames = fieldnames(struct); % get the matching field names
end;
lno = 0; % line counter
while(~feof(fh))
    inline = strtrim(fgetl(fh)); % read each line
    lno = lno + 1;
    if(length(inline) == 0) % handle empty lines
        continue;
    end;
    if(findstr(inline(1),'%;:')) % first character comment (various types allowed)
        continue;
    end;
    if(strmatch(inline, '#array', 'exact'))
        disp('array mode');
        arrayflag = 1;
        arrayindex = 1;
        continue;
    end;
    if(strmatch(inline, '#endarray', 'exact'))
        disp('END array mode');
        arrayflag = 0;
        arrayindex = 1;
        continue;
    end;
    if(strmatch(inline, '#increment', 'exact'))
        if(arrayflag == 0)
            fprintf(1, 'config_parse: attempting to increment non-array ? \n');
            continue;
        end;
        arrayindex = arrayindex + 1;
        continue;
    end;
    arrayindex
    if(inline(1) == '[')
        section = strtok(inline,'[]');
    else
        lhs = strtok(inline, '%');
        try
            eval([lhs ';']); % evaluate as a matlab statement... simple
        catch
                fprintf(1, 'Config error on input line %d: %s\n', lno, lhs);
                continue;
        end;
        target = strtok(lhs, ' =');
        switch(nargin)
            case 1
                if(arrayflag == 0)
                    eval(sprintf('result.%s.%s = %s;', section, target, target));
                else
                    eval(sprintf('result.%s(%d).%s = %s;', section, arrayindex, target, target));
                end;

            otherwise

                if(isempty(strmatch(target, fnames, 'exact')))
                    fprintf(1, '%s is not a member of input structure; value ignored\n', target);
                else
                    if(arrayflag == 0)
                        eval(sprintf('result.%s.%s = %s;', section, target, target));
                    else
                        eval(sprintf('result.%s(%d).%s = %s;', section, arrayindex, target, target));
                    end;
                end;
        end;
    end;

end;
fclose(fh);

